#include <wifi.hpp>
//
#include <tcp_client.hpp>
#include <wifi_text_log.hpp>

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT	   BIT1

#if defined(CONFIG_TAR4ESP32)

static EventGroupHandle_t s_wifi_event_group;

static void wifi_sta_set_ipaddr(ip_event_got_ip_t* event)
{
	esp_netif_ip_info_t ip;
	memcpy(&ip, &event->ip_info, sizeof(esp_netif_ip_info_t));

	LOG("Got IP: " IPSTR "\n", IP2STR(&ip.ip));
	LOG("Got NM: " IPSTR "\n", IP2STR(&ip.netmask));
	LOG("Got GW: " IPSTR "\n", IP2STR(&ip.gw));

	if (event->ip_info.ip.addr == ipaddr_addr(LOCAL_IP))
	{
		LOG("ip addr is already %s\n", LOCAL_IP);
		return;
	}

	ip.ip.addr = ipaddr_addr(LOCAL_IP);

	if (esp_netif_dhcpc_stop(event->esp_netif) != ESP_OK)
	{
		return;
	}

	if (esp_netif_set_ip_info(event->esp_netif, &ip) != ESP_OK)
	{
		return;
	}
	LOG("set ip %s ok.\n", LOCAL_IP);

#if TCP_TEXTLOG_ENABLE
	// 启动 wifi text log
	WifiTextLog* wifiTextLog = WifiTextLog::Instance();
	wifiTextLog->Start();
	LOG("start wifi text log.\n");
#endif

#if TCP_CLIENT_ENABLE
	// 启动tcp client
	TcpClient* tcpClient = TcpClient::Instance();
	tcpClient->Start();
	LOG("start tcp client.\n");
#endif
}

static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
	if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
	{
		esp_wifi_connect();
		LOG("Station started\n");
	}
	if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED)
	{
		LOG("Station connected\n");
	}
	else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
	{
		xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);

		ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
		LOG("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
		// 设置IP地址
		wifi_sta_set_ipaddr(event);
	}
}

#endif

static Wifi* s_Wifi = nullptr;

Wifi* Wifi::Instance(void)
{
	if (s_Wifi == nullptr)
	{
		s_Wifi = new Wifi();
	}
	return s_Wifi;
}

Wifi::Wifi()
	: m_Ssid(WIFI_SSID)
	, m_Passwd(WIFI_PASSWD)
#if defined(CONFIG_TAR4ESP32)
	, esp_netif_ap(nullptr)
	, esp_netif_sta(nullptr)
#endif
{
}

Wifi::~Wifi()
{
}

void Wifi::Start(void)
{
#if !WIFI_AP_ENABLE && !WIFI_STA_ENABLE
	return;
#endif

#if defined(CONFIG_TAR4ESP32)

	while (1)
	{
		esp_event_loop_delete_default();
		esp_wifi_disconnect();
		esp_wifi_stop();
		esp_wifi_deinit();
		esp_netif_deinit();

		// 初始化网络
		esp_netif_init();

		esp_event_loop_create_default();
		// 创建事件组
		s_wifi_event_group = xEventGroupCreate();

		// 初始化网络配置
		wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
		esp_wifi_init(&cfg);
		// 设置为STATION模式
		esp_wifi_set_mode(WIFI_MODE_APSTA);
		// 关闭低功耗
		esp_wifi_set_ps(WIFI_PS_NONE);

#if WIFI_AP_ENABLE
		StartApSoft();
#endif

#if WIFI_STA_ENABLE
		StartStation();
#endif

		// 启动WIFI网络
		esp_wifi_start();

#if WIFI_STA_ENABLE
		// 配置事件组，10秒超时
		EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, (10 * 1000) / portTICK_PERIOD_MS);

		if (bits & WIFI_CONNECTED_BIT)
		{
			LOG("connected to wifi\n");
			break;
		}
		else if (bits & WIFI_FAIL_BIT)
		{
			LOG("Failed to connect to wifi\n");
		}
		else
		{
			LOG("UNEXPECTED EVENT %x\n", bits);
		}
#else
		break;
#endif
	}

#if WIFI_AP_ENABLE
	esp_netif_napt_enable(esp_netif_ap);
#endif

#if WIFI_STA_ENABLE
	esp_netif_set_default_netif(esp_netif_sta);
	esp_netif_dhcpc_start(esp_netif_sta);
#endif

#else
	// 启动 wifi text log
	WifiTextLog* wifiTextLog = WifiTextLog::Instance();
	wifiTextLog->Start();
	LOG("start wifi text log.\n");

	// 启动tcp client
	TcpClient* tcpClient = TcpClient::Instance();
	tcpClient->Start();
	LOG("start tcp client.\n");
#endif
}

void Wifi::StartStation(void)
{
#if defined(CONFIG_TAR4ESP32)
	wifi_config_t wifi_sta_config;
	memset(&wifi_sta_config, 0, sizeof(wifi_config_t));
	strcpy((char*)wifi_sta_config.sta.ssid, m_Ssid.c_str());
	strcpy((char*)wifi_sta_config.sta.password, m_Passwd.c_str());

	// 注册主要事件
	esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, &wifi_event_handler, this, NULL);
	esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &wifi_event_handler, this, NULL);
	esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, this, NULL);

	// 创建sta
	if (esp_netif_sta != nullptr)
	{
		esp_netif_destroy_default_wifi(esp_netif_sta);
		esp_netif_sta = nullptr;
	}
	esp_netif_sta = esp_netif_create_default_wifi_sta();
	// 配置STATION模式网络环境
	esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config);
#endif
}

void Wifi::StartApSoft(void)
{
#if defined(CONFIG_TAR4ESP32)
	wifi_config_t wifi_ap_config;
	memset(&wifi_ap_config, 0, sizeof(wifi_config_t));

	strncpy((char*)wifi_ap_config.ap.ssid, WIFI_AP_NAME, strlen(WIFI_AP_NAME));
	strncpy((char*)wifi_ap_config.ap.password, WIFI_AP_PWD, strlen(WIFI_AP_PWD));
	wifi_ap_config.ap.ssid_len		   = strlen(WIFI_AP_NAME);
	wifi_ap_config.ap.channel		   = 1;
	wifi_ap_config.ap.max_connection   = 4;
	wifi_ap_config.ap.authmode		   = WIFI_AUTH_WPA2_PSK;
	wifi_ap_config.ap.pmf_cfg.required = false;

	// 注册主要事件
	esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL);

	// 创建ap
	if (esp_netif_ap != nullptr)
	{
		esp_netif_destroy_default_wifi(esp_netif_ap);
		esp_netif_ap = nullptr;
	}
	esp_netif_ap = esp_netif_create_default_wifi_ap();
	esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config);
#endif
}